package cn.zz.veggie.persistence.repository;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import cn.zz.veggie.application.assembler.ShopQuoteAssembler;
import cn.zz.veggie.model.query.ShopQuoteQuery;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.core.PropertiesRoleMappingListener;
import org.springframework.stereotype.Repository;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.zz.comm.core.types.query.PageQuery;
import cn.zz.comm.exception.classes.FatalErrorException;
import cn.zz.comm.util.CollectorUtil;
import cn.zz.comm.util.DateTimeUtil;
import cn.zz.comm.util.NumberUtil;
import cn.zz.veggie.model.domain.ShopQuote;
import cn.zz.veggie.model.query.QuoteQuery;
import cn.zz.veggie.persistence.dao.ShopQuoteMapper;
import lombok.RequiredArgsConstructor;

/**
 * @author zhongq
 * @since 2024/7/28
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class ShopQuoteRepository {

	private final ShopQuoteMapper shopQuoteMapper;

	public ShopQuote findById(Integer id) {
		if (!NumberUtil.isPositive(id)) {
			return null;
		}
		return shopQuoteMapper.selectById(id);
	}

	public Map<Integer, ShopQuote> findByIds(Collection<Integer> ids) {
		if (CollectionUtil.isEmpty(ids)) {
			return Collections.emptyMap();
		}
		final List<ShopQuote> records = shopQuoteMapper.selectBatchIds(ids);
		return CollectorUtil.btmByKeyFun(records, ShopQuote::getId);
	}

	public ShopQuote findOne(ShopQuoteQuery query) {
		final LambdaQueryWrapper<ShopQuote> queryWrapper = query.toQueryWrapper();
		return shopQuoteMapper.selectOne(queryWrapper, false);
	}

	public List<ShopQuote> findByQuery(ShopQuoteQuery query, PageQuery page) {
		final LambdaQueryWrapper<ShopQuote> queryWrapper = query.toQueryWrapper();
		final Page<ShopQuote> queryPage = query.toPage(page);
		List<ShopQuote> records = shopQuoteMapper.selectList(queryPage, queryWrapper);
		page.setTotal((int) queryPage.getTotal());
		return records;
	}

	public void save(ShopQuote quote) {
		Objects.requireNonNull(quote);
		if (quote.getId() == null) {
			// insert
			final int effect = shopQuoteMapper.insert(quote);
			if (effect != 1) {
				throw new FatalErrorException("created shop quote fail ");
			}
			log.info("created shop quote  for {} - {}", quote.getShopId(), quote.getId());
		} else {
			// update
			final int effect = shopQuoteMapper.updateById(quote);
			if (effect != 1) {
				throw new FatalErrorException("update shop quote  fail ");
			}
			log.info("updated shop quote  for {} - {}", quote.getShopId(), quote.getId());
		}
	}

	public void deleteById(Integer id) {
		Objects.requireNonNull(id);
		final int effect = shopQuoteMapper.deleteById(id);
		if (effect != 1) {
			log.error("delete");
			throw new FatalErrorException("delete shop quote  fail ");
		}
		log.info("delete shop quote  for {}", id);
	}

	public void deleteByIds(Collection<Integer> ids) {
		if (CollUtil.isEmpty(ids)) {
			return;
		}
		final int effect = shopQuoteMapper.deleteByIds(ids);
		log.info("delete shop quote  for {}", effect);
	}

	public Map<Integer, ShopQuote> findProductQuote(Integer shopId, Collection<Integer> productIds) {
		Objects.requireNonNull(shopId);
		if (CollUtil.isEmpty(productIds)) {
			return Collections.emptyMap();
		}
		final ShopQuoteQuery query = new ShopQuoteQuery();
		query.shopId = shopId;
		query.productIds = productIds;
		final List<ShopQuote> quotes = findByQuery(query, PageQuery.all());
		return CollectorUtil.btmByKeyFun(quotes, ShopQuote::getProductId);
	}

	public void updateOrSaveQuotes(Integer shopId, Map<Integer, Integer> currQuoteMap) {
		Map<Integer, ShopQuote> currProductQuotes = findProductQuote(shopId, currQuoteMap.keySet());
		final List<ShopQuote> insertOrUpdateRecords = currQuoteMap.entrySet().stream().map(entry -> {
			final Integer productId = entry.getKey();
			final Integer price = entry.getValue();
			final ShopQuote shopQuote = currProductQuotes.get(productId);
			if (shopQuote == null) {
				return ShopQuoteAssembler.create(null, shopId, productId, price);
			}
			if (Objects.equals(shopQuote.getPrice(), price)) {
				return null;
			}
			shopQuote.setPrice(price);
			return shopQuote;
		}).filter(Objects::nonNull).toList();
		shopQuoteMapper.insertOrUpdate(insertOrUpdateRecords);
	}

}